package cn.tedu.csmall.product.webapi.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect // 使得当前类是一个切面类
@Component // 使得Spring可以创建当前类的对象并进行管理
public class TimeAspect {

    // 关于切面方法：
    // -- 访问权限：应该是公有的
    // -- 返回值类型：当使用@Around时，使用Object类型，否则，使用void
    // -- 方法名称：自定义
    // -- 参数列表：当使用@Around时，添加ProceedingJoinPoint类型的参数，否则，为空
    // 关于ProceedingJoinPoint：
    // -- 可称为“连接点”，用于调用切面连接到的目标的方法
    // -- 调用proceed()方法时，相当于执行了切面连接到的目标的方法，例如某个业务方法
    // -- 所以，调用此方法时，切不可捕获异常
    // -- 否则，其它的调用者（例如控制器）将不会知道此异常的出现，就无法向客户端响应错误的结果
    // -- 并且，一定要获取proceed()方法的返回值，它相当于切面连接到的目标的方法的返回值
    // -- proceed()方法的返回值必须作为此切面方法的返回值
    // -- 否则，相当于切面连接到的目标的方法没有返回有效结果
    // 关于execution表达式
    // -- 用于匹配需要切面连接到的目标方法
    // 关于@Around注解
    // -- 是AOP中Advice的一种：“环绕”，用于表示在连接到的目标方法之前和之后
    // -- 在AOP中还有其它Advice，例如@Before / @After / @AfterReturning / @AfterThrowing
    @Around("execution(* cn.tedu.csmall.product.service.*.*(..))")
    public Object serviceMethodTimer(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();

        Object result = pjp.proceed();
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();

        long end = System.currentTimeMillis();
        System.out.println("方法声明：" + signature);
        System.out.println("参数值：" + Arrays.toString(args));
        System.out.println("执行耗时：" + (end - start) + "毫秒");
        return result;
    }

}
